package cc.rengu.redp.flowable.service;

import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.flowable.domain.*;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.task.Comment;
import org.flowable.idm.api.User;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

/**
 * 工作流引擎服务层
 *
 * @author xushitang
 */
public interface SysWorkFlowService {

    /**
     * 保存用户
     *
     * @param userId
     */
    void saveUser(String userId);

    /**
     * 删除用户
     *
     * @param userId
     */
    void deleteUser(String userId);

    /**
     * 保存组
     *
     * @param groupName
     */
    void saveGroup(String groupName);

    /**
     * 删除组
     *
     * @param groupName
     */
    void deleteGroup(String groupName);

    /**
     * 建立用户与组的关系
     *
     * @param userId
     * @param groupName
     */
    void createMembership(String userId, List<String> groupName);

    /**
     * 获取多个用户组里的全部用户
     *
     * @param groups
     * @return
     */
    List<User> getAllByRoles(List<String> groups);

    /**
     * 获取可用的已部署的流程定义信息
     *
     * @param userId
     * @return
     */
    List<ProcessDefinition> getAvailableProcesses(String userId);


    /**
     * 获取可用的已部署的流程定义信息
     * @return
     */
    List<ProcessDefinition> getAvailableProcesses();
    /**
     * 获取所有已部署的流程定义信息
     *
     * @return
     */
    List<ProcessDefinition> getAllProcesses();

    /**
     * 获取已部署的流程定义信息
     * @param procDefKey
     * @return
     */
    ProcessDefinition getProcessDefinitionByProcDefKey(String procDefKey);

    /**
     * 获取最新已部署的bpmn模型
     * @param procDefKey
     * @return
     */
    BpmnModel getBpmnModelFromRepositoryByProcDefKey(String procDefKey);

    /**
     * 根据流程定义Key获取流程定义中的所有结束事件
     *
     * @param procDefKey
     * @return endEventId, endEventName
     */
    Map<String, String> getEndEventsByProcDefId(String procDefKey);

    /**
     * 根据任务id完成任务, 并设置相关的流程变量
     *
     * @param taskId      任务id
     * @param workFlowVar 流程变量
     */
    void completeTaskByTaskId(String taskId, WorkFlowVar workFlowVar);

    /**
     * 根据任务id完成任务, 并设置相关的流程变量
     *
     * @param taskId
     * @param workFlowVar
     * @param assignee    在完成时设置受理人
     */
    void completeTaskByTaskId(String taskId, WorkFlowVar workFlowVar, String assignee);

    /**
     * 根据流程id完成任务, 并设置相关的流程变量
     *
     * @param procInstId  流程id
     * @param workFlowVar 流程变量
     *                    适用于后台处理UserTask
     */
    void completeTaskByProcInstId(String procInstId, WorkFlowVar workFlowVar);

    /**
     * 根据流程id完成任务, 并设置相关的流程变量
     *
     * @param procInstId  流程id
     * @param workFlowVar 流程变量
     * @param assignee    在完成时设置受理人
     *                    适用于后台处理UserTask
     */
    void completeTaskByProcInstId(String procInstId, WorkFlowVar workFlowVar, String assignee);

    /**
     * 完成"接收任务"
     * @param procInstId
     * @param receiveTaskDefId
     */
    void completeReceiveTask(String procInstId, String receiveTaskDefId);

    /**
     * 使用流程实例获取当前作业id
     *
     * @param procInstId 流程实例id
     * @return 活动id，即流程图中的任务节点名
     */
    List<String> getTaskIdByProcInstId(String procInstId);

    /**
     * 使用流程实例获取当前活动id(任务名)
     *
     * @param procInstId 流程实例id
     * @return 活动id，即流程图中的任务节点名
     */
    List<String> getNodeIdByProcInstId(String procInstId);

    /**
     * 查询待办列表
     *
     * @param userId
     * @param queryText
     * @param pageNo
     * @param pageSize
     * @return
     */
    List<WaitingToDo> getWaitingToDo(String userId, String queryText, int pageNo, int pageSize);

    /**
     * 查询待办列表（总数）
     *
     * @param userId
     * @param queryText
     * @return
     */
    long getWaitingToDoTotal(String userId, String queryText);

    /**
     * 获取节点定义ID
     *
     * @param taskId 流程任务ID
     * @return
     */
    String getNodeIdByTaskId(String taskId);

    /**
     * 获取流程实例ID
     *
     * @param taskId
     * @return
     */
    String getProcInstByTaskId(String taskId);

    /**
     * 根据流程实例ID返回流程名称
     *
     * @param procInstId 流程实例ID
     * @return 流程名称
     */
    String getProcDefNameByProcInstId(String procInstId);

    /**
     * 获取流程实例ID对应的流程定义ID
     *
     * @param procInstId
     * @return
     */
    String getProcDefIdByProcInstId(String procInstId);

    /**
     * 获取任务ID对应的流程定义ID
     *
     * @param taskId
     * @return 流程定义ID
     */
    String getProcDefIdByTaskId(String taskId);

    /**
     * 获取流程实例ID对应的流程定义ID（带版本号）
     *
     * @param procInstId
     * @return
     */
    String getProcDefIdVerIdByInstId(String procInstId);

    /**
     * 获取任务ID对应的流程定义ID(带版本号）
     *
     * @param taskId
     * @return 流程定义ID
     */
    String getProcDefVerIdByTaskId(String taskId);

    /**
     * 根据流程实例id查询批注信息
     *
     * @param processInstId 流程定义id
     * @return 批注信息列表
     */
    List<Comment> getCommentByProcInstId(String processInstId);

    /**
     * @param taskId 任务id
     * @return 批注信息
     * @Description 根据taskid查询批注信息
     */
    String getCommentByTaskId(String taskId);

    /**
     * 根据流程实例id查询当前taskId
     *
     * @param procInstId
     * @return 当前任务id
     */
    List<String> getCurrTaskByProcInstId(String procInstId);

    /**
     * 根据流程实例获取当前的流程变量
     *
     * @param taskId 任务ID
     * @param clazz  流程变量类类型
     * @return 流程变量类
     * @author xushitang
     */
    <T extends WorkFlowVar> T getVariable(String taskId, Class<T> clazz);

    /**
     * 设置任务的流程变量
     *
     * @param taskId      任务id
     * @param workFlowVar 流程变量
     */
    void setVariable(String taskId, WorkFlowVar workFlowVar);

    /**
     * 根据任务id设置assignee
     *
     * @param taskId   任务id
     * @param assignee 办理人
     */
    void setAssignee(String taskId, String assignee);

    /**
     * 根据taskid设置candidates
     *
     * @param taskId     任务id
     * @param candidates 办理人集合
     */
    void setCandidate(String taskId, List<String> candidates);

    /**
     * 获取流程实例的发起者 (运行时获取）
     *
     * @param procInstId
     */
    String getApplicantByProcInstId(String procInstId);

    /**
     * 获取历史路径上最新同名节点的历史经办人
     *
     * @param taskId 当前taskId
     * @return 历史经办人
     */
    String getHistAssigneeInThisProcInstByTaskId(String taskId);

    /**
     * 获取历史路径上最新同名节点的历史经办人
     *
     * @param procInstId 当前流程实例ID
     * @param nodeId     同名节点
     * @return
     */
    String getHistAssigneeInThisProcInstByNodeId(String procInstId, String nodeId);

    /**
     * 增加批注信息
     *
     * @param taskId   任务id
     * @param userName 审批人
     * @param message  批注信息
     */
    void setComment(String processInstanceId, String taskId, String userName, String message);

    /**
     * 删除指定taskId的批注
     *
     * @param taskId
     */
    void delComment(String taskId);

    /**
     * @param processDefinitionKey 流程定义ID，与流程图对应。用于根据业务主键快速映射流程。
     * @param applicant            流程发起人， 同时也是首任务办理人
     * @param businessKey          业务主键。用于区分同类流程中，不同业务主键的流程实例。
     * @param workFlowVar          流程变量
     * @return 成功，返回流程ID。失败，返回null
     * @Description 根据 (流程名, 申请人, 业务ID) 启动申请流程
     */
    String startProcess(String processDefinitionKey, String applicant, String businessKey, WorkFlowVar workFlowVar);


    /**
     * 获取部署库中最新的流程定义
     *
     * @param procDefId
     * @return
     */
    ProcessDefinition getProcDefByProcDefKey(String procDefId);

    /**
     * 获取流程部署记录
     *
     * @param deployId
     * @return
     */
    Deployment getDeploymentById(String deployId);

    /**
     * 流程路径查询
     *
     * @param procInstId 流程实例ID
     * @return
     */
    List<HisActivity> getHisActByProcInstId(String procInstId);

    /**
     * 流程路径查询（记录总数）
     *
     * @param procInstId 工作流实例ID
     * @return
     */
    Long getHisActByProcInstIdTotal(String procInstId);

    /**
     * 强行结束指定流程实例ID
     *
     * @param procInstId 流程实例id
     * @author dikai
     */
    void terminateProcInst(String procInstId);

    /**
     * 删除指定流程实例ID的历史踪迹记录
     *
     * @param procInstId 流程实例id
     */
    void terminateProcessFromHis(String procInstId);

    /**
     * 查询taskId的后驱分支（即流程定义中的流出分支列表）
     * @param taskId
     * @param getDataAndCheck  因为要读取流程数据并判断Aviator，本部分不应该在引擎模块中进行，故设置回调方法
     *                         String，String，Boolean -> 参数1：流程定义ID, 参数2：Aviator表达式，参数3：返回值类型
     * @return
     */
    List<NextToDo> getOutComeListByTaskId(String taskId, BiFunction<String, String, Boolean> getDataAndCheck);

    /**
     * 根据taskId和seqId查询线条的自定义配置
     * @param taskId
     * @param seqId
     * @return
     */
    CustomSequenceFlow getCustomSequenceFlowByTaskIdAndSeqId(String taskId, String seqId);

    /**
     * 部署（发布）流程定义
     *
     * @param modelId
     * @throws RedpException
     */
    void deployFromModeler(String modelId) throws RedpException;

    /**
     * 获取当前taskId的扩展信息
     *
     * @param taskId
     * @return
     */
    CustomUserNode getCustomNodeByTaskId(String taskId);

    /**
     * 通过流程定义ID获取节点扩展信息（从部署中获取）
     *
     * @param procDefIdVerId
     * @return
     */
    CustomStartNode getStartCustomNodeByProcDefId(String procDefIdVerId);

    /**
     * 通过流程定义ID获取节点扩展信息（从部署中获取）
     *
     * @param procDefKey
     * @return
     */
    CustomStartNode getStartCustomNodeByProcDefKey(String procDefKey);

    /**
     * 获取指定分支的目标用户节点的扩展信息（从部署中获取）
     *
     * @param sequenceId
     * @return
     */
    CustomNodeVo getTargetUserTaskCustomNode(String sequenceId, String taskId);

    /**
     * 获取指定分支的目标用户节点的扩展信息（从部署中获取，用于流程未启动的起始事件）
     *
     * @param procDefKey
     * @return
     */
    CustomNodeVo getTargetUserTaskCustomNode(String procDefKey);

    /**
     * 获取当前用户流转中的任务单
     *
     * @param userId
     * @param queryText
     * @param pageNum
     * @param pageSize
     * @return
     */
    List<WaitingToDo> getInTransitProcess(String userId, String queryText, int pageNum, int pageSize);

    /**
     * 获取当前用户流转中的任务单据总数
     *
     * @param userId
     * @param queryText
     * @return
     */
    Long getInTransitProcessCount(String userId, String queryText);

    /**
     * 获取当前用户发起的已完成任务单
     *
     * @param userId
     * @param queryText
     * @param pageNum
     * @param pageSize
     * @return
     */
    List<FinishedProcess> getLatelyClosedProcess(String userId, String queryText, int pageNum, int pageSize);

    /**
     * 获取当前用户发起的已完成任务单总数
     *
     * @param userId
     * @param processDefName
     * @return
     */
    Long getLatelyClosedProcessCount(String userId, String processDefName);

    /**
     * 查询所有任务单
     *
     * @param procDefName
     * @param applicant
     * @param status
     * @param pageNum
     * @param pageSize
     * @return
     */
    List<ProcessManager> getAllProcessInstance(String procDefName, String applicant, String status, int pageNum, int pageSize);

    /**
     * 查询所有任务单（记录总数）
     *
     * @param procDefName
     * @param applicant
     * @param status
     * @return
     */
    Long getAllProcessInstanceCount(String procDefName, String applicant, String status);

    /**
     * 删除模型部署
     * @param procDefKey
     * @param version
     * @param deleteProcessInstants
     */
    void deleteDeployment(String procDefKey, String version, boolean deleteProcessInstants);

    /**
     * 挂起所有版本的流程部署
     * @param procDefKey
     * @param suspendProcessInstances
     * @param suspensionDate
     */
    void suspendDeployment(String procDefKey, boolean suspendProcessInstances, LocalDate suspensionDate);

    /**
     * 激活所有版本的流程部署
     * @param procDefKey
     * @param activateProcessInstances
     * @param activationDate
     */
    void activeDeployment(String procDefKey, boolean activateProcessInstances, LocalDate activationDate);

    /**
     * 获取当前最新流程部署的挂起状态
     * @param procDefKey
     * @return 若为null，即指定procDefKey未部署
     */
    Boolean getSuspendStatusByProcDefKey(String procDefKey);

    /**
     * 获取date日期之前的已经完成的历史流程实例
     * @param date
     * @return
     */
    List<HistoricProcessInstance> getFinishedProcInst(Date date);

    /**
     * 根据流程实例ID级联删除历史表数据
     * @param procInstId
     */
    void deleteHistoryProcInst(String procInstId);
}
